Imports System.Net.Sockets
Imports System.Text

Public Enum UserStatus
	Online
	DoNotDisturb
	Offline
End Enum

'====================================================================
'			RemoteUser ----- has a -----> UserConnection.
'====================================================================

Public Class RemoteUser

	Implements IDisposable

	'====================================================================

	Public Event ReceivedText(ByVal Sender As RemoteUser, ByVal Message As String)
	Public Event Connected(ByVal Sender As RemoteUser)
	Public Event Disconnected(ByVal Sender As RemoteUser)
	Public Event StatusChanged(ByVal Sender As RemoteUser)

	'====================================================================

#Region " Constructors and destructors "

	Public Sub New(ByVal Addr As String)
		Address = Addr
		Name = Addr
	End Sub

	Public Sub New(ByVal UserName As String, ByVal Addr As String)
		Address = Addr
		Name = UserName
	End Sub

	'====================================================================

	Protected Overrides Sub Finalize()
		MyBase.Finalize()
		Dispose()
	End Sub

	Public Sub Dispose() Implements System.IDisposable.Dispose
		Disconnect()
	End Sub

#End Region

#Region " Connect / Disconnect "

	'====================================================================

	Public Sub ConnectInitiate(ByVal LocalUserName As String, ByVal LocalUserAddress As String)
		If IsOnline() Then Exit Sub

		Dim NewClient As TcpClient

		Try
			NewClient = New TcpClient(Me.Address, PortNum)
			Connection = New UserConnection(NewClient)

			SendMessage(MessageType.Connect, LocalUserName & "|" & LocalUserAddress)
			Status = UserStatus.Online
			RaiseEvent Connected(Me)

		Catch e As Exception
			Disconnect()
		End Try
	End Sub

	'====================================================================

	Public Sub ConnectRespond(ByVal ExistingConnection As UserConnection)
		Connection = ExistingConnection
		Status = UserStatus.Online
		RaiseEvent Connected(Me)
	End Sub

	'====================================================================

	Private Sub mConnection_Terminated(ByVal Sender As Agent.UserConnection) Handles mConnection.Terminated
		Disconnect()
		RaiseEvent Disconnected(Me)
	End Sub

	Public Sub Disconnect()	'Implements IRemoteUser.Disconnect
		If Not Connection Is Nothing Then
			Connection.Dispose()
			Connection = Nothing
		End If
		Status = UserStatus.Offline
	End Sub

#End Region

	'====================================================================

	Private WithEvents mConnection As UserConnection
	Protected Property Connection() As UserConnection
		Get
			Return mConnection
		End Get
		Set(ByVal Value As UserConnection)
			mConnection = Value
		End Set
	End Property

	'====================================================================

#Region " Sending data "

	Public Sub SendText(ByVal Message As String)
		If IsOnline() Then
			SendMessage(MessageType.Chat, Message)
		End If
	End Sub

	Public Sub SendStatus(ByVal NewStatus As UserStatus)
		Dim StatusString As String
		Select Case NewStatus
			Case UserStatus.Online
				StatusString = msgStatusOnline
			Case UserStatus.DoNotDisturb
				StatusString = msgStatusDoNotDisturb
		End Select
		SendMessage(MessageType.Status, StatusString)
	End Sub

	Private Enum MessageType
		Connect
		Chat
		Status
	End Enum

	Private Sub SendMessage(ByVal Purpose As MessageType, Optional ByVal Param As String = "")
		Dim Message As StringBuilder = New StringBuilder(Param.Length + 8)

		Select Case Purpose
			Case MessageType.Connect
				Message.Append(msgConnect)
			Case MessageType.Chat
				Message.Append(msgChat)
			Case MessageType.Status
				Message.Append(msgStatus)
		End Select

		Message.Append("|")
		Message.Append(Param)

		SendData(Message.ToString)
	End Sub

	'====================================================================

	Private Sub SendData(ByVal Data As String)
		If Not Connection Is Nothing Then
			Connection.SendData(Data)
		End If
	End Sub

#End Region

	'====================================================================

#Region " Receiving data "

	Private Sub mConnection_LineReceived(ByVal Sender As Agent.UserConnection, ByVal Data As String) Handles mConnection.LineReceived
		ProcessCommand(Data)
	End Sub

	'====================================================================

	' Process the command received from the server, and take appropriate action.
	Private Sub ProcessCommand(ByVal strMessage As String)

		' Message parts are divided by "|"  Break the string into an array accordingly.
		Dim dataArray() As String = strMessage.Split("|"c)

		' dataArray(0) is the command.
		Select Case dataArray(0)

			Case msgChat
				' Received a chat message, notify the container.
				RaiseEvent ReceivedText(Me, dataArray(1))

			Case msgStatus
				Select Case dataArray(1)
					Case msgStatusOnline
						Me.Status = UserStatus.Online
					Case msgStatusDoNotDisturb
						Me.Status = UserStatus.DoNotDisturb
				End Select
				RaiseEvent StatusChanged(Me)
		End Select

	End Sub

	'====================================================================

#End Region

	'====================================================================

#Region " Properties: Name, Address, Status "

	'====================================================================
	' Status
	'====================================================================

	Private mStatus As UserStatus = UserStatus.Offline
	Public Property Status() As Agent.UserStatus
		Get
			Return mStatus
		End Get
		Set(ByVal Value As Agent.UserStatus)
			mStatus = Value
		End Set
	End Property

	Public Function IsOnline() As Boolean
		Return Not Status = UserStatus.Offline
	End Function

	'====================================================================
	' Name
	'====================================================================

	Private mName As String
	Public Property Name() As String
		Get
			Return mName
		End Get
		Set(ByVal Value As String)
			mName = Value
		End Set
	End Property

	'====================================================================
	' Address
	'====================================================================

	Private mAddress As String
	Public Property Address() As String
		Get
			Return mAddress
		End Get
		Set(ByVal Value As String)
			mAddress = Value
		End Set
	End Property

	'====================================================================
#End Region

End Class